﻿using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using CMS6Tools.Management.Model;
using WeifenLuo.WinFormsUI.Docking;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.ProcessConfiguration.Client; 
using Microsoft.TeamFoundation.VersionControl.Client;
using CMS6Tools.Common.TFS;

namespace CMS6Tools.Management
{
    public partial class KPIForm : DockContent
    {
        const string StageFieldReferenceName = "Vision.Stage";
        const string CategoryFieldReferenceName = "Vision.Category";
        const string SeverityFieldReferenceName = "Microsoft.VSTS.Common.Severity";
        const string IterationPathFieldReferenceName = "System.IterationPath";
        const string ReleasePrefix = "Release ";
        const string TBDIterationName = "TBD";
        const string TicketCategory_Implementation = "Implementation";
        const string TicketCategory_Wireframe = "Wireframe";
        const string TicketCategory_Suggestion = "Suggestion";
        const string TagSourceCodeFolderath = "$/CMS 6/CMS 6/tags";
        readonly DateTime MinDateTime = new DateTime(2015, 1, 1);
        const float HoursAmount = 30.0F;
        

        #region Ctor
        public KPIForm()
        {
            InitializeComponent();
        }
        #endregion

        #region Load
        private void KPIForm_Load(object sender, EventArgs e)
        {
            PatchHotfixDataGridView.AutoGenerateColumns = false;
            KPIBugDataGridView.AutoGenerateColumns = false;

            //var tfsUrl = ConfigurationManager.AppSettings["codeChangeTfsDefaultCollectionURL"] ?? "http://andromeda:8080/tfs/CmsCollection";
            //var credential = CredentialCache.DefaultNetworkCredentials;
            //var tfsTeamProjectCollection = new TfsTeamProjectCollection(new Uri(tfsUrl), credential);

            //tfsTeamProjectCollection.EnsureAuthenticated();
            //if (tfsTeamProjectCollection.HasAuthenticated)
            //{
            //    AuthenticatedTfsTeamProjectCollection = tfsTeamProjectCollection; 
            //}
            //else
            //{
            //    AuthenticatedTfsTeamProjectCollection = null;
            //    MessageBox.Show("Authenticated failed.");
            //    return;
            //}

            var workItemStore = Util.AuthenticatedTfsTeamProjectCollection.GetService<WorkItemStore>();
            ProjectComboBox.ValueMember = "ID";
            ProjectComboBox.DisplayMember = "Name";
            ProjectComboBox.DataSource = workItemStore.Projects.OfType<Project>()
            //    .Select(a => new { 
            //    a.Name,
            //    a.Id,
            //    a.Uri
            //})
            .ToList();
        }
        #endregion

        private void SelectAllIterationCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            foreach (TreeNode treeNode in IterationTreeView.Nodes)
            {
                treeNode.Checked = SelectAllIterationCheckBox.Checked;
            }
        }

        private void ProjectComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (ProjectComboBox.SelectedIndex >= 0)
            {
                IterationTreeView.Nodes.Clear();
                var selectedProjectID = (int)((dynamic)ProjectComboBox.SelectedItem).Id;
                var workItemStore = Util.AuthenticatedTfsTeamProjectCollection.GetService<WorkItemStore>();
                var project = workItemStore.Projects.OfType<Project>().Where(a => a.Id == selectedProjectID).FirstOrDefault();
                if (project != null)
                {
                    var rootNodes = project.IterationRootNodes.OfType<Node>();
                    BindIterationTreeView(IterationTreeView.Nodes, rootNodes, true);
                    if (IterationTreeView.Nodes.Count > 0)
                        IterationTreeView.Nodes[0].EnsureVisible();
                }
            }
        }
         
        private void BindIterationTreeView(TreeNodeCollection treeNodeCollection, IEnumerable<Node> nodes, bool needCheckBox)
        {
            foreach (var node in nodes.OrderByDescending(a=>a.Name))
            {
                if (node.Name.Equals(TBDIterationName, StringComparison.InvariantCultureIgnoreCase))
                    continue;

                if (node.Name.StartsWith("Release 2014"))
                    continue;

                var childTreeNode = new TreeNode(node.Name);
                childTreeNode.Tag = node;
                treeNodeCollection.Add(childTreeNode);
                if (!needCheckBox)
                    HideCheckBox(IterationTreeView, childTreeNode);
                if (node.HasChildNodes)
                {
                    BindIterationTreeView(childTreeNode.Nodes, node.ChildNodes.OfType<Node>(), false);
                    childTreeNode.ExpandAll();
                }
            }
        }

        private void IterationTreeView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Nodes.Count > 0)
            {
            }
        }

        private float GetTeamCapacityByHour(IWebAccessProxy proxy, WorkItemStore workItemStore, Project project, Node iterationNode)
        {
            return TFSTasks.TfsTask.GetTeamCapacityByHour(proxy, workItemStore, project, iterationNode).Capacity;

            // old logic
            /*
            var list = new List<Node>();
            if (iterationNode.ChildNodes.Count > 0)
                list.AddRange(iterationNode.ChildNodes.Cast<Node>());
            else
                list.Add(iterationNode);

            var result = 0f;
            var developmentActivity = "Development";
            foreach (var node in list)
            {
                var team = proxy.GetTeamCapacitySettings(project, string.Empty, true, node.Path);
                var totalDays = team.IterationEndDate.Subtract(team.IterationStartDate).Days + 1; // as the enddate always 12:00:00 AM

                var teamDaysOffDateList = GetDateList(team.TeamCapacity.TeamDaysOffDates);
                var teamDaysOff = teamDaysOffDateList.Count;

                var teamDaysAvaiableDateList = new List<DateTime>();
                for (var currentDate = team.IterationStartDate; currentDate <= team.IterationEndDate; currentDate = currentDate.AddDays(1))
                {
                    if (currentDate.DayOfWeek == DayOfWeek.Saturday || currentDate.DayOfWeek == DayOfWeek.Sunday)
                        continue;
                    if (teamDaysOffDateList.Contains(currentDate))
                        continue;
                    teamDaysAvaiableDateList.Add(currentDate);
                }

                var availableDays = teamDaysAvaiableDateList.Count;
                var finalDays = 0f;
                foreach (var member in team.TeamCapacity.TeamMemberCapacityCollection)
                {
                    if (member.Activity == developmentActivity)
                    {
                        var memberDaysOffDateList = GetDateList(member.DaysOffDates);
                        var memberAvailableDays = 0;
                        if (memberDaysOffDateList.Any())
                        {
                            foreach (var date in teamDaysAvaiableDateList)
                            {
                                if (memberDaysOffDateList.Contains(date))
                                    continue;
                                memberAvailableDays++;
                            }
                        }
                        else
                        {
                            memberAvailableDays = availableDays;
                        }

                        finalDays += member.Capacity * memberAvailableDays;
                    }
                }
                result += finalDays;
            }
            return result;
           */
        }

        private List<DateTime> GetDateList(DaysOffDates[] daysOffDates)
        {
            var dateList = new List<DateTime>();
            foreach (var daysOff in daysOffDates)
            {
                for (var currentDate = daysOff.Start; currentDate <= daysOff.End; currentDate = currentDate.AddDays(1))
                {
                    if (!dateList.Contains(currentDate))
                        dateList.Add(currentDate);
                }
            }
            return dateList;
        }
        private void KPIBugButton_Click(object sender, EventArgs e)
        {
            var selectedProject = (Project)ProjectComboBox.SelectedItem;
            var selectedProjectName = selectedProject.Name;
            var selectedProjectUri = selectedProject.Uri;
            var selectIterationNodes = GetSelectIterationNodes(IterationTreeView.Nodes.OfType<TreeNode>());
            if (!selectIterationNodes.Any())
            {
                MessageBox.Show("Please select at least 1 iteration!");
                return;
            }

            var teamService = Util.AuthenticatedTfsTeamProjectCollection.GetService<TfsTeamService>();
            var workItemStore = Util.AuthenticatedTfsTeamProjectCollection.GetService<WorkItemStore>();
            var commonStructureService = Util.AuthenticatedTfsTeamProjectCollection.GetService<ICommonStructureService4>();
            var configurationService = Util.AuthenticatedTfsTeamProjectCollection.GetService<TeamSettingsConfigurationService>();
            var versionControlService = Util.AuthenticatedTfsTeamProjectCollection.GetService<VersionControlServer>();

            #region Bugs
            var proxy = WebAccessProxyProvider.GetProxy();

            var team = teamService.GetDefaultTeam(selectedProjectUri.ToString(), new List<string>());

            var queryBuilder = new StringBuilder();
            queryBuilder.Append("Select System.Id, System.Title from workitems where ");
            queryBuilder.AppendFormat(" [System.TeamProject] = '{0}' ", selectedProjectName);
            queryBuilder.Append(" AND [System.WorkItemType]='Bug' AND NOT(System.Title Contains 'Build Failure') ");

            var bugModelList = new List<KPIQualityBugModel>();
            var iterationInfoModelList = new List<IterationInfoModel>();
            var iterationQueryBuilder = new StringBuilder();
            foreach (var iterationNode in selectIterationNodes)
            {
                var iterationInfo = commonStructureService.GetNode(iterationNode.Uri.ToString());
                var hasStartDate = iterationInfo.StartDate.HasValue;
                var hasFinishDate = iterationInfo.FinishDate.HasValue;
                if (hasStartDate || hasFinishDate)
                {
                    var teamCapacity = GetTeamCapacityByHour(proxy, workItemStore, selectedProject, iterationNode); 

                    bugModelList.AddRange(
                        Enum.GetValues(typeof(BugSeverity)).Cast<BugSeverity>().Select(a => new KPIQualityBugModel
                        {
                            IterationPath = iterationNode.Path,  // like: CMS 6\Release 2015.2.629.0\Sprint 79
                            Release = FormatRelease(iterationInfo.Name),// iterationInfo.Path like:  \CMS 6\Iterations\Release 2015.2.629.0\Sprint 79
                            Severity = a,
                            NumberOfDevelopment = 0,
                            NumberOfProduct = 0,
                            NumberOfReleaseQA = 0,
                            Total = 0,
                            Capacity = teamCapacity
                        }));

                    if (iterationQueryBuilder.Length > 0)
                        iterationQueryBuilder.Append(" OR ");
                    iterationQueryBuilder.Append("(");
                    if (hasStartDate)
                    {
                        iterationQueryBuilder.AppendFormat("System.CreatedDate>='{0}'", iterationInfo.StartDate.Value.AddDays(-1));
                        if (hasFinishDate)
                            iterationQueryBuilder.AppendFormat(" AND ");
                    }
                    if (hasFinishDate)
                    {
                        iterationQueryBuilder.AppendFormat("System.CreatedDate<'{0}'", iterationInfo.FinishDate.Value.AddDays(1));
                    }
                    iterationQueryBuilder.Append(")");


                    iterationInfoModelList.Add(new IterationInfoModel
                    {
                        IterationPath = iterationNode.Path,
                        Release = FormatRelease(iterationInfo.Name),
                        StartDate = iterationInfo.StartDate.Value,
                        FinishDate = iterationInfo.FinishDate.Value,
                        Capacity = teamCapacity
                    });
                }

            }
            queryBuilder.AppendFormat(" AND ({0})", iterationQueryBuilder.ToString());

            var workItemCollection = workItemStore.Query(queryBuilder.ToString());
            //var selectedCategories = new List<string>();
            //if (TicketCategoryImplementationcheckBox.Checked)
            //    selectedCategories.Add(TicketCategory_Implementation); 
            //if (TicketCategoryNonImplementationcheckBox.Checked)
            //    selectedCategories.Add(TicketCategory_Wireframe);

            var selectedImplementationCategory = TicketCategoryImplementationcheckBox.Checked;
            var selectedNonImplementationCategory = TicketCategoryNonImplementationcheckBox.Checked;

            foreach (WorkItem item in workItemCollection)
            {
                var stageField = item.Fields[StageFieldReferenceName];
                var stage = (stageField.Value ?? "").ToString();

                var categoryField = item.Fields[CategoryFieldReferenceName];
                var category = (categoryField.Value ?? "").ToString();
                //if (selectedCategories.Any() && !selectedCategories.Any(a => category.Equals(a, StringComparison.InvariantCultureIgnoreCase)))

                var fit = false;
                if(selectedImplementationCategory && selectedNonImplementationCategory)
                {
                    fit = true;
                }
                else if (selectedImplementationCategory)
                {
                    fit = TicketCategory_Implementation.Equals(category, StringComparison.CurrentCultureIgnoreCase);
                }
                else if (selectedNonImplementationCategory)
                {
                    fit = !TicketCategory_Implementation.Equals(category, StringComparison.CurrentCultureIgnoreCase);
                }
                if (!fit)
                    continue;

                var severityField = item.Fields[SeverityFieldReferenceName];
                var severitySegments = (severityField.Value ?? "").ToString().Split('-');
                var severity = BugSeverity.Medium.ToString();
                if (severitySegments.Count() >= 2)
                    severity = severitySegments[1].Trim();

                var createdDate = item.CreatedDate;

                var iterationPathField = item.Fields[IterationPathFieldReferenceName];
                var iterationPath = (iterationPathField.Value ?? "").ToString();

                var iterationInfoModel = iterationInfoModelList.First(a => createdDate.AddDays(1) >= a.StartDate && createdDate.AddDays(-1) < a.FinishDate);

                var bugModel = bugModelList.First(a => a.Severity.ToString().Equals(severity, StringComparison.InvariantCultureIgnoreCase)
                                                     && a.IterationPath.Equals(iterationInfoModel.IterationPath, StringComparison.InvariantCultureIgnoreCase));

                bugModel.Total++;
                var bugStage = BugStage.Development;
                if (Enum.TryParse<BugStage>(stage, out bugStage))
                {
                    switch (bugStage)
                    {
                        case BugStage.Product:
                            bugModel.NumberOfProduct++;
                            break;
                        case BugStage.ReleaseQA:
                            bugModel.NumberOfReleaseQA++;
                            break;
                        case BugStage.Development:
                        default:
                            bugModel.NumberOfDevelopment++;
                            break;
                    }
                }
                else
                {
                    bugModel.NumberOfReleaseQA++;
                }

            }

            bugModelList = bugModelList.OrderBy(a => a.Release).ToList();

            KPIBugDataGridView.DataSource = bugModelList.OrderByDescending(a => a.Release).ToList();

            BindCharts(bugModelList);
            #endregion

            #region Patch & Hotfix
            var patchHotfixModelList = new List<KPIQualityPatchHotfixModel>();
            foreach (var iterationModel in iterationInfoModelList)
            {
                var releaseTagFolder = string.Format("{0}/{1}", TagSourceCodeFolderath, iterationModel.Release);
                var patchReleaseTagFolder = string.Format("{0}/Patch", releaseTagFolder);
                var hotfixReleaseTagFolder = string.Format("{0}/Hotfix", releaseTagFolder);
                var patchHotfixModel = new KPIQualityPatchHotfixModel()
                {
                    Release = iterationModel.Release,
                    Capacity = iterationModel.Capacity,
                    IterationPath = iterationModel.IterationPath
                };
                try
                {
                    var patchItems = versionControlService.GetItems(patchReleaseTagFolder + "/*");
                    patchHotfixModel.Patch = patchItems.Items.Count();
                    var hotfixItem = versionControlService.GetItems(hotfixReleaseTagFolder + "/*");
                    patchHotfixModel.Hotfix = hotfixItem.Items.Count();
                }
                catch
                {
                }
                patchHotfixModelList.Add(patchHotfixModel);
            }
            PatchHotfixDataGridView.DataSource = patchHotfixModelList.OrderByDescending(a => a.Release).ToList();
            BindPatchHotfixChart(patchHotfixModelList.OrderBy(a => a.Release), PatchHotfixChart);
            #endregion
        }

        private void BindCharts(IEnumerable<KPIQualityBugModel> bugModelList)
        {
            BindBugsSeverityChart(bugModelList, BugSeverity.Critical, CriticalChart);
            BindBugsSeverityChart(bugModelList, BugSeverity.High, HighChart);
            BindBugsSeverityChart(bugModelList, BugSeverity.Medium, MediumChart);
            BindBugsSeverityChart(bugModelList, BugSeverity.Low, LowChart);

            BindBugsTotalChartBySeverity(bugModelList);

            BindBugsTotalChartByStage(bugModelList);

            BindBugsTotalChart(bugModelList);

            BindBugsTotalWeightedChart(bugModelList);
        }

        private void BindBugsTotalChartBySeverity(IEnumerable<KPIQualityBugModel> bugModelList)
        {
            var chart = BugsTotalChartBySeverity;
            var bugModelListGroupByRelease = bugModelList.GroupBy(a=>a.Release).ToList();
            chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisX.Title = "Release";
            chart.ChartAreas[0].AxisX.TitleFont = new Font(chart.ChartAreas[0].AxisX.TitleFont, FontStyle.Bold);

            chart.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisY.Title = string.Format("{0}", "All Stages Bugs");
            chart.ChartAreas[0].AxisY.TitleFont = new Font(chart.ChartAreas[0].AxisY.TitleFont, FontStyle.Bold);

            foreach (var series in chart.Series)
            {
                series.Points.Clear();
                series.Font = new System.Drawing.Font(series.Font, FontStyle.Bold);
                series.IsValueShownAsLabel = true;
            }

            foreach (var bugModel in bugModelListGroupByRelease)
            {
                var criticalBugModel = bugModel.First(a => a.Severity == BugSeverity.Critical);
                chart.Series["Critical"].Points.AddXY(bugModel.Key, Math.Round(criticalBugModel.Total / (criticalBugModel.Capacity / HoursAmount), 2));

                var highBugModel = bugModel.First(a => a.Severity == BugSeverity.High);
                chart.Series["High"].Points.AddXY(bugModel.Key, Math.Round(highBugModel.Total / (highBugModel.Capacity / HoursAmount), 2));

                var mediumBugModel = bugModel.First(a => a.Severity == BugSeverity.Medium);
                chart.Series["Medium"].Points.AddXY(bugModel.Key, Math.Round(mediumBugModel.Total / (mediumBugModel.Capacity / HoursAmount), 2));

                var lowBugModel = bugModel.First(a => a.Severity == BugSeverity.Low);
                chart.Series["Low"].Points.AddXY(bugModel.Key, Math.Round(lowBugModel.Total / (lowBugModel.Capacity / HoursAmount), 2)); 
            }
        }

        private void BindBugsTotalChartByStage(IEnumerable<KPIQualityBugModel> bugModelList)
        {
            var chart = BugsTotalChartByStage;
            var bugModelListGroupByRelease = bugModelList.GroupBy(a => a.Release).ToList();
            chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisX.Title = "Release";
            chart.ChartAreas[0].AxisX.TitleFont = new Font(chart.ChartAreas[0].AxisX.TitleFont, FontStyle.Bold);

            chart.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisY.Title = string.Format("{0}", "All Severity Bugs");
            chart.ChartAreas[0].AxisY.TitleFont = new Font(chart.ChartAreas[0].AxisY.TitleFont, FontStyle.Bold);

            foreach (var series in chart.Series)
            {
                series.Points.Clear();
                series.Font = new System.Drawing.Font(series.Font, FontStyle.Bold);
                series.IsValueShownAsLabel = true;
            }

            foreach (var bugModel in bugModelListGroupByRelease)
            {
                var capacity = bugModel.First().Capacity;

                var developmentStageBugs = bugModel.Aggregate(0, (seed, a) => seed + a.NumberOfDevelopment);
                chart.Series["Development"].Points.AddXY(bugModel.Key, Math.Round(developmentStageBugs / (capacity / HoursAmount), 2));

                var releaseQAStageBugs = bugModel.Aggregate(0, (seed, a) => seed + a.NumberOfReleaseQA);
                chart.Series["Release QA"].Points.AddXY(bugModel.Key, Math.Round(releaseQAStageBugs / (capacity / HoursAmount), 2));

                var productStageBugs = bugModel.Aggregate(0, (seed, a) => seed + a.NumberOfProduct);
                chart.Series["Product"].Points.AddXY(bugModel.Key, Math.Round(productStageBugs / (capacity / HoursAmount), 2));
            }
        }

        private void BindBugsTotalChart(IEnumerable<KPIQualityBugModel> bugModelList)
        {
            var chart = BugsTotalChart;
            var bugModelListGroupByRelease = bugModelList.GroupBy(a => a.Release).ToList();
            chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisX.Title = "Release";
            chart.ChartAreas[0].AxisX.TitleFont = new Font(chart.ChartAreas[0].AxisX.TitleFont, FontStyle.Bold);

            chart.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisY.Title = string.Format("{0}", "All Bugs");
            chart.ChartAreas[0].AxisY.TitleFont = new Font(chart.ChartAreas[0].AxisY.TitleFont, FontStyle.Bold);

            foreach (var series in chart.Series)
            {
                series.Points.Clear();
                series.Font = new System.Drawing.Font(series.Font, FontStyle.Bold);
                series.IsValueShownAsLabel = true;
            }

            foreach (var bugModel in bugModelListGroupByRelease)
            {
                var capacity = bugModel.First().Capacity;

                var totalBugs = bugModel.Aggregate(0, (seed, a) => seed + a.Total);
                chart.Series["Total"].Points.AddXY(bugModel.Key, Math.Round(totalBugs / (capacity / HoursAmount), 2));
            }
        }
        
        private void BindBugsTotalWeightedChart(IEnumerable<KPIQualityBugModel> bugModelList)
        {
            var chart = BugsTotalChartWithWeight;
            var bugModelListGroupByRelease = bugModelList.GroupBy(a => a.Release).ToList();
            chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisX.Title = "Release";
            chart.ChartAreas[0].AxisX.TitleFont = new Font(chart.ChartAreas[0].AxisX.TitleFont, FontStyle.Bold);

            chart.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisY.Title = string.Format("{0}", "All Bugs");
            chart.ChartAreas[0].AxisY.TitleFont = new Font(chart.ChartAreas[0].AxisY.TitleFont, FontStyle.Bold);

            foreach (var series in chart.Series)
            {
                series.Points.Clear();
                series.Font = new System.Drawing.Font(series.Font, FontStyle.Bold);
                series.IsValueShownAsLabel = true;
            }

            foreach (var bugModel in bugModelListGroupByRelease)
            {
                var capacity = bugModel.First().Capacity;

                var totalBugs = 0.0;

                totalBugs += (bugModel.Where(a => a.Severity == BugSeverity.Critical).Select(a => (int?)a.Total).FirstOrDefault() ?? 0) * 2;
                totalBugs += (bugModel.Where(a => a.Severity == BugSeverity.High).Select(a => (int?)a.Total).FirstOrDefault() ?? 0) * 1.5;
                totalBugs += (bugModel.Where(a => a.Severity == BugSeverity.Medium).Select(a => (int?)a.Total).FirstOrDefault() ?? 0) * 1;
                totalBugs += (bugModel.Where(a => a.Severity == BugSeverity.Low).Select(a => (int?)a.Total).FirstOrDefault() ?? 0) * 0.5;

                chart.Series["TotalWithWeight"].Points.AddXY(bugModel.Key, Math.Round(totalBugs / (capacity / HoursAmount), 2));
            }
        }

        private void BindBugsSeverityChart(IEnumerable<KPIQualityBugModel> bugModelList, BugSeverity severity, Chart chart)
        {
            var severityBugModelList = bugModelList.Where(a => a.Severity == severity).ToList();
            chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisX.Title = "Release";
            chart.ChartAreas[0].AxisX.TitleFont = new Font(chart.ChartAreas[0].AxisX.TitleFont, FontStyle.Bold);

            chart.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisY.Title = string.Format("{0}", severity);
            chart.ChartAreas[0].AxisY.TitleFont = new Font(chart.ChartAreas[0].AxisY.TitleFont, FontStyle.Bold);

            chart.Series[0].Points.Clear();
            chart.Series[1].Points.Clear();
            chart.Series[2].Points.Clear();

            chart.Series[0].Font = new System.Drawing.Font(chart.Series[0].Font, FontStyle.Bold);
            chart.Series[1].Font = new System.Drawing.Font(chart.Series[1].Font, FontStyle.Bold);
            chart.Series[2].Font = new System.Drawing.Font(chart.Series[2].Font, FontStyle.Bold);

            chart.Series[0].IsValueShownAsLabel = true;
            chart.Series[1].IsValueShownAsLabel = true;
            chart.Series[2].IsValueShownAsLabel = true;

            foreach (var bugModel in severityBugModelList)
            {
                chart.Series["Development"].Points.AddXY(bugModel.Release, Math.Round(bugModel.NumberOfDevelopment / (bugModel.Capacity / HoursAmount), 2));
                //chart.Series[0].Points[chart.Series[0].Points.Count - 1].Label = bugModel.NumberOfDevelopment.ToString();

                chart.Series["Release QA"].Points.AddXY(bugModel.Release, Math.Round(bugModel.NumberOfReleaseQA / (bugModel.Capacity / HoursAmount), 2));
                //chart.Series[1].Points[chart.Series[1].Points.Count - 1].Label = bugModel.NumberOfReleaseQA.ToString();

                chart.Series["Product"].Points.AddXY(bugModel.Release, Math.Round(bugModel.NumberOfProduct / (bugModel.Capacity / HoursAmount), 2));
                //chart.Series[2].Points[chart.Series[2].Points.Count - 1].Label = bugModel.NumberOfDevelopment.ToString();
            }

        }

        private void BindPatchHotfixChart(IEnumerable<KPIQualityPatchHotfixModel> patchHotfixModelList, Chart chart)
        {
            chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisX.Title = "Release";
            chart.ChartAreas[0].AxisX.TitleFont = new Font(chart.ChartAreas[0].AxisX.TitleFont, FontStyle.Bold);

            chart.ChartAreas[0].AxisY.Interval = 1;
            chart.ChartAreas[0].AxisY.Maximum = 4;
            chart.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            chart.ChartAreas[0].AxisY.Title = "Number";
            chart.ChartAreas[0].AxisY.TitleFont = new Font(chart.ChartAreas[0].AxisY.TitleFont, FontStyle.Bold);

            chart.Series[0].Points.Clear();
            chart.Series[1].Points.Clear(); 

            chart.Series[0].Font = new System.Drawing.Font(chart.Series[0].Font, FontStyle.Bold);
            chart.Series[1].Font = new System.Drawing.Font(chart.Series[1].Font, FontStyle.Bold); 

            chart.Series[0].IsValueShownAsLabel = true;
            chart.Series[1].IsValueShownAsLabel = true;

            foreach (var patchHotfix in patchHotfixModelList)
            {
                chart.Series["Patch"].Points.AddXY(patchHotfix.Release, patchHotfix.Patch);

                chart.Series["Hotfix"].Points.AddXY(patchHotfix.Release, patchHotfix.Hotfix);
            }
        }

        private List<Node> GetSelectIterationNodes(IEnumerable<TreeNode> treeNodes)
        {
            var selectedNodes = new List<Node>();

            foreach(var treeNode in treeNodes)
            {
                if(treeNode.Checked)
                {
                    selectedNodes.Add(treeNode.Tag as Node);
                }
                if(treeNode.Nodes.Count >0)
                {
                    selectedNodes.AddRange(GetSelectIterationNodes(treeNode.Nodes.OfType<TreeNode>()));
                }
            }

            return selectedNodes;
        }

        private string FormatRelease(string releaseName)
        {
            if (string.IsNullOrEmpty(releaseName))
                return releaseName;
            if (releaseName.StartsWith(ReleasePrefix))
                return releaseName.Substring(ReleasePrefix.Length).Trim();
            return releaseName;
        }

        internal class IterationInfoModel
        {
            public string Release { get; set; }
            public string IterationPath { get; set; }
            public DateTime StartDate { get; set; }
            public DateTime FinishDate { get; set; }
            public float Capacity { get; set; }
        }

        #region Interop
        private const int TVIF_STATE = 0x8;
        private const int TVIS_STATEIMAGEMASK = 0xF000;
        private const int TV_FIRST = 0x1100;
        private const int TVM_SETITEM = TV_FIRST + 63;

        [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
        private struct TVITEM
        {
            public int mask;
            public IntPtr hItem;
            public int state;
            public int stateMask;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpszText;
            public int cchTextMax;
            public int iImage;
            public int iSelectedImage;
            public int cChildren;
            public IntPtr lParam;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
                                                 ref TVITEM lParam);

        /// <summary>
        /// Hides the checkbox for the specified node on a TreeView control.
        /// </summary>
        private void HideCheckBox(TreeView treeView, TreeNode node)
        {
            TVITEM tvi = new TVITEM();
            tvi.hItem = node.Handle;
            tvi.mask = TVIF_STATE;
            tvi.stateMask = TVIS_STATEIMAGEMASK;
            tvi.state = 0;
            SendMessage(treeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
        }
        #endregion

        
    }
}
